package lambdasinaction.chap9.my;

/**
 * 不断演进的 API
 * 为了理解为什么一旦 API 发布之后，它的演进就变得非常困难
 * 我们假设你是一个流行 Java绘图库的设计者
 * 你的库中包含了一个 Resizable 接口，
 * 它定义了一个简单的可缩放形状必须支持的很多方法，
 * 比如：setHeight/setWidth/getHeight/getWidth/setAbsoluteSize
 * 此外，你还提供了几个额外的实现，如正方形、长方形。
 * 由于你的库非常流行，你的一些用户使用 Resizable 接口创建了他们自己感兴趣的实现，比如椭圆。
 * 发布 API 几个月之后，你突然意识到 Resizable 接口遗漏了一些功能。
 * 比如，如果接口提供一个 setRelativeSize 方法，可以接受参数实现对形状的大小进行调整，
 * 那么接口的易用性会更好。
 * 你会说这看起来很容易啊。为 Resizable 接口添加 setRelativeSize方法，再更新 Square 和 Rectangle 的实现就好了。
 * 不过，事情并非如此简单！你要考虑已经使用了你接口的用户，
 * 他们已经按照自身的需求实现了 Resizable 接口，他们该如何应对这一的变更呢？
 * 非常不幸，你无法访问，也无法改动他们实现了 Resizable 接口的类。
 * 这也是 Java 库的设计者需要改进 JavaAPI时面对的问题。
 * 让我们以一个具体的实例为例，深入探讨修改一个已发布接口的种种后果。
 *
 * @author Fish
 * @since 0.0.1 2018/8/10 15:10
 */
public interface MyResizable extends MyDrawable{

  int getWidth();
  int getHeight();
  void setWidth(int width);
  void setHeight(int height);
  void setAbsoluteSize(int width, int height);

  /**
   * 第二版 API
   * 库上线使用几个月之后，你收到很多请求，要求你更新 Resizable 的实现，
   * 让 Square、Rectangle 以及其他的形状都能支持 setRelativeSize 方法
   * 为了满足这些新的需求，你发布了第二版 API
   *
   * 第二版 API 添加了一个新方法
   * 为 Resizable 接口添加新方法改进 API，
   * 再次编译应用时会遭遇错误，因为它依赖的 Resizable 接口发生了变化
   *
   * 用户面临的窘境
   * 对 Resizable 接口的更新导致了一系列的问题。
   * 首先，接口现在要求它所有的实现类添加 setRelativeSize 方法的实现。
   * 但是用户最初实现的 Ellipse 类并未包含 setRelativeSize 方法。
   * 向接口添加新方法是二进制兼容的，这意味着如果不重新编译该类，
   * 即使不实现新的方法，
   * 现有类的实现依旧可以运行。
   * 不过，用户可能修改他的游戏，在他的 Utils.paint 方法中调用 setRelativeSize 方法，
   * 因为 paint 方法接受一个 Resizable 对象列表作为参数。
   * 如果传递的是一个 Ellipse 对象，程序就会抛出了一个运行时错误，
   * 因为它并未实现 setRelativeSize方法。
   *
   * 最后，更新已发布 API 会导致向后兼容性问题
   * 这就是为什么对现存 API 的演进，比如官方发布的 Java Collection API，会给用户带来麻烦。
   * 当然，还有其他方式能够实现对 API 的改进，但是都不是明智的选择。
   * 比如，你可以为你的 API 创建不同的发布版本，同时维护老版本和新版本，
   * 但这是非常费时费力的。
   * 原因如下，其一：这增加了你作为类库的设计者维护类库的复杂度。
   * 其次，类库的用户不得不同时使用一套代码的两个版本，而这会增大内存的消耗，延长程序的载入时间，
   * 因为这种方式下项目使用的类文件数量更多了
   */
//  void setRelativeSize(int wFactor, int hFactor); //

  /**
   * 概述默认方法
   * 我们已经了解了向已发布的 API 添加方法
   * 对现存代码实现会造成多大的损害。
   * 默认方法是 Java8中引入的一个新特性，
   * 希望能借此以兼容的方式改进 API。
   * 现在，接口包含的方法签名在它的实现类也可以不提供实现。
   * 那么，谁来具体实现这些方法呢？
   * 实际上，缺失的方法实现会作为接口的一部分由实现类集成（所以命名为默认实现）
   * 而无需由实现类提供。
   * 默认方法由 default 修饰符修饰，并像类中声明的其他方法一样包含方法体。
   * @param wFactor
   * @param hFactor
   */
  default void setRelativeSize(int wFactor, int hFactor) {

  }
}
